﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Hive.Bot.Tasks;
using Hive.Core;

namespace Hive.Bot.Behaviours
{
    public class ExploreBehavior : IBehaviour
    {
        private int taskLimit = 0;

        public ExploreBehavior(int limit)
        {
            this.taskLimit = limit;
        }

        public List<ITask> GenerateTasks()
        {
            var result = new List<ITask>();
            var targets = new List<Location>();

            bool[,] visited = new bool[Env.Map.Height, Env.Map.Width];

            visited.Iter((i, j, v) => visited[i, j] = Env.Map[i, j] != Tile.Unseen);

            var route = GetRoute(visited);
            var currentTaskLimit = CalculateTaskLimit();
            while (route.Any())
            {
                Log.Write("Route Length {0} Explore to {1} destination visited {2}",
                    route.Count, route.Last().ToString(), visited[route.Last().Row, route.Last().Col]);

                result.Add(new ExploreTask(route.Last()));
                targets.Add(route.Last());
                if (taskLimit > 0 && result.Count >= currentTaskLimit)
                    break;
                MarkArea(visited, route.Last(), Env.ViewRadius2 / 4);

                route = GetRoute(visited);
            }
            Log.Write("Created {0} explore tasks with tasklimit {1}/{2}", result.Count, currentTaskLimit, taskLimit);
            //LogVisited(visited, targets);
            return result;
        }

        private int CalculateTaskLimit()
        {
            double unseenRatio = Env.Map.TileCountUnseen / (double)Env.Map.TileCount;
            var result = 1.0;
            if (unseenRatio > 0.5 && unseenRatio <= 1)
            {
                result = taskLimit * 2 * (1 - unseenRatio);
            }
            else if (unseenRatio >= 0 && unseenRatio <= 0.5)
            {
                result = taskLimit * unseenRatio * 2;
            }

            if ((int)result == 0 && taskLimit == 0)
                result = 1;
            Log.Write("Unseen tiles ratio: {0}. Current explore task limit: {1}", unseenRatio, (int)result);
            return (int)result + 5;
        }

        private void LogVisited(bool[,] visited, List<Location> targets)
        {
            var sb = new StringBuilder("ExploreBehaviour::GenerateTasks()");
            sb.AppendLine();
            for (var i = 0; i < visited.Height(); i++)
            {
                for (var j = 0; j < visited.Width(); j++)
                {
                    var c = visited[i, j] == true ? " " : ".";
                    if (targets.Any(t => t.Row == i && t.Col == j))
                        c = "X";
                    sb.Append(c);
                }
                sb.AppendLine();
            }
            Log.Write(sb.ToString());
        }

        private List<Location> GetRoute(bool[,] visited)
        {
            var origin = Env.MyHills.First();

            var route = Env.Map.DirectionTo(origin, l => Env.Map[l] == Tile.Unseen && !visited.At(l) );

            return route;
        }

        private void MarkArea(bool[,] visited, Location location, int radius)
        {
            foreach (var offset in Env.GetVisibilityOffsets())
            {
                var l = (location + offset).Normalize();
                visited[l.Row, l.Col] = true;
            }
        }
    }

}

